'use strict'
var __ = require('lodash')

var C = 150
var WEIGHT = [35,30,60,50,40,10,25] 
var POWER = [10,40,30,50,35,40,30]
var LEN = 7
var maxPower = 0
var maxGene = []
var maxi = 0;
const POPMAX = 32, P_XOVER = 0.8, P_MUTATION = 0.15, MAXGENERATIONS = 20
var pop = []

class Gene{
    constructor(gene){
        this.gene = gene;
        this.fitness = 0;
        this.rf = 0;
        this.cf = 0;
    }
}

function reverseGene(index){
    let mcc = Math.round(Math.random() * 7)
    for(let i = 0; i < mcc; i++){
        let gi = Math.floor(Math.random() * 7) 
        pop[index].gene[gi] = 1 - pop[index].gene[gi]
    }
}

function mutation(){
    for(let i=0; i<POPMAX; i++){
        let p = Math.random();
        if(p < P_MUTATION){
            reverseGene(i)
        }
    }
}

function exChgOver(first,second){
    let ecc = Math.round(Math.random() * 7)
    for(let i=0; i<ecc; i++){
        let idx = Math.floor(Math.random() * 7)
        let tg = pop[first].gene[idx]
        pop[first].gene[idx] = pop[second].gene[idx]
        pop[second].gene[idx] = tg
    }
}

function crossover(){
    let first = -1;
    for(let i=0; i<POPMAX; i++){
        let p = Math.random();
        if(p < P_XOVER){
            if(first < 0){
                first = i;
            }else{
                exChgOver(first,i)
                first = -1;
            }
        }
    }
}

function selectBetter(totalFitness){
    let lastCf = 0;
    let newPop = []
    for(let i = 0; i<POPMAX; i++){
        pop[i].rf = pop[i].fitness / totalFitness;
        pop[i].cf = lastCf + pop[i].rf;
        lastCf = pop[i].cf;
console.log(pop[i].gene.join(',')+'--'+pop[i].fitness +'--'+pop[i].rf + '--' +pop[i].cf)
    }
    for(let i=0; i<POPMAX; i++){
        let p = Math.random();
        if(p < pop[0].cf){
            newPop[i] = pop[0];
        }else{
            for(var j = 0; j<POPMAX-1; j++){
                if(p >= pop[j].cf && p < pop[j+1].cf){
                    newPop[i] = pop[j+1];
                    break;
                }
            }
        }
    }
    pop = [] 
    for(let i=0; i< newPop.length; i++){
        pop.push(__.cloneDeep(newPop[i]))
    }
}

function envaluateFitness(max){
    let totalFitness = 0;
    for(let i=0; i<POPMAX; i++ ){
        let tw = 0;
        pop[i].fitness = 0;
        for(let j=0; j<LEN; j++){
            if(pop[i].gene[j]){
                tw += WEIGHT[j]
                pop[i].fitness += POWER[j]
            }
        }
        if(tw > C){
            pop[i].fitness = 1;
        }else{
            if(pop[i].fitness > maxPower){
                maxPower = pop[i].fitness;
                maxGene = __.cloneDeep(pop[i].gene);
                maxi = max;
            }
        }
        totalFitness += pop[i].fitness
    }
    return totalFitness;
}

function initGenes(){
    let count = 0, maxFit = 100;
    while(count < POPMAX){
        let tmp = [],pall = 0;
        for(let j = 0; j<LEN; j++){
            let pow = Math.round(Math.random())
            tmp.push(pow);
            if(pow == 1)
                pall += POWER[j]
        }
        if(pall < maxFit){
            let g = new Gene(tmp)
            pop.push(g)
            count++
        }
    }
}

initGenes();
var f = envaluateFitness(0)
for(let i=0; i<MAXGENERATIONS; i++){
console.log('-----'+i+':'+f)
    selectBetter(f)
    crossover()
    mutation()
    f= envaluateFitness(i)
}
console.log(maxi + '--' + maxPower + ' <=> ' + maxGene.join(','));
